package com.tcm.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tcm.common.enums.CachePrefix;
import com.tcm.config.AppProperties;
import com.tcm.entity.*;
import com.tcm.entity.bo.UserCacheBo;
import com.tcm.entity.dto.param.NoteUpdateDto;
import com.tcm.entity.resp.PageR;
import com.tcm.entity.vo.BookListResult;
import com.tcm.entity.vo.NoteDetailResp;
import com.tcm.entity.vo.NoteListResult;
import com.tcm.mapper.BookItemMapper;
import com.tcm.mapper.TeacherMapper;
import com.tcm.service.*;
import com.tcm.mapper.NoteMapper;
import com.tcm.utils.RedisUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 学生笔记业务实现类
* @author Guqier
* @description 针对表【ts_note(学生笔记表)】的数据库操作Service实现
* @createDate 2023-08-22 16:14:15
*/
@Service
public class NoteServiceImpl extends ServiceImpl<NoteMapper, Note>
    implements NoteService{

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private SubjectItemService subjectItemService;

    @Autowired
    private ClozeItemService clozeItemService;

    @Autowired
    private BookService bookService;

    @Autowired
    private BookItemMapper bookItemMapper;

    @Autowired
    private CodeService codeService;

    @Autowired
    private ImageService imageService;

    @Autowired
    private ItemService itemService;

    @Autowired
    private CollectService collectService;

    @Autowired
    private RoleService roleService;

    @Autowired
    private TeacherMapper teacherMapper;

    @Autowired
    private UserService userService;

    /**
     * 学生保存笔记
     * @param dto 笔记参数
     * @param currUserId 当前登录用户ID
     * @return 处理结果，true为成功，false为数据库操作失败
     */
    @Override
    @Transactional
    public boolean saveNote(NoteUpdateDto dto, Long currUserId){
        // 获取学生信息
        UserCacheBo userCacheBo = redisUtil.getCacheObject(CachePrefix.PC_USER_TOKEN.getCacheKey(currUserId.toString()));
        // 查询笔记是否存在
        LambdaQueryWrapper<Note> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Note::getAccount, userCacheBo.getAccount());
        queryWrapper.eq(Note::getItemId, dto.getItemId());
        Note note = this.getOne(queryWrapper);
        boolean flag;
        if (note == null){
            Note one = new Note();
            one.setAccount(userCacheBo.getAccount());
            one.setContent(dto.getContent());
            one.setType(dto.getType());
            one.setItemId(dto.getItemId());
            one.setCreateUser(currUserId);
            one.setUpdateUser(currUserId);
            flag = this.save(one);
        }else {
            note.setContent(dto.getContent());
            note.setUpdateUser(currUserId);
            flag = this.updateById(note);
        }
        return flag;
    }

    /**
     * 删除笔记
     * @param itemId 题目ID
     * @param currUserId 当前登录用户ID
     * @return 处理结果，true为成功
     */
    @Override
    @Transactional
    public boolean removeNote(Long itemId, Long currUserId){
        // 获取学生信息
        UserCacheBo userCacheBo = redisUtil.getCacheObject(CachePrefix.PC_USER_TOKEN.getCacheKey(currUserId.toString()));
        // 删除笔记
        LambdaQueryWrapper<Note> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Note::getAccount, userCacheBo.getAccount());
        queryWrapper.eq(Note::getItemId, itemId);
        return this.remove(queryWrapper);
    }

    /**
     * 根据题目获取笔记
     * @param itemId 题目ID
     * @param currUserId 当前登录用户ID
     * @return 笔记信息
     */
    @Override
    public NoteUpdateDto getNoteByItemId(Long itemId, Long currUserId){
        // 获取学生信息
        UserCacheBo userCacheBo = redisUtil.getCacheObject(CachePrefix.PC_USER_TOKEN.getCacheKey(currUserId.toString()));
        // 查询笔记
        LambdaQueryWrapper<Note> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Note::getAccount, userCacheBo.getAccount());
        queryWrapper.eq(Note::getItemId, itemId);
        Note note = this.getOne(queryWrapper);
        if (note == null){
            return null;
        }
        NoteUpdateDto noteUpdateDto = new NoteUpdateDto();
        BeanUtils.copyProperties(note, noteUpdateDto);
        return noteUpdateDto;
    }

    /**
     * 学生获取笔记列表
     * @param currUserId 当前登录用户ID
     * @return 笔记列表
     */
    @Override
    public List<NoteListResult> getStuNoteList(Long currUserId){
        // 获取学生信息
        UserCacheBo userCacheBo = redisUtil.getCacheObject(CachePrefix.PC_USER_TOKEN.getCacheKey(currUserId.toString()));
        // 查询当前学生所有笔记
        LambdaQueryWrapper<Note> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Note::getAccount, userCacheBo.getAccount());
        queryWrapper.orderByDesc(Note::getUpdateTime);
        List<Note> notes = this.list(queryWrapper);

        return this.transferNoteToListResult(notes);
    }

    /**
     * 获取笔记详细
     * @param current 当前笔记序数
     * @param currUserId 当前登录用户ID
     * @return 笔记详细
     */
    @Override
    public PageR<NoteDetailResp> getNoteDetail(Integer current, Long currUserId){
        // 获取学生信息
        UserCacheBo userCacheBo = redisUtil.getCacheObject(CachePrefix.PC_USER_TOKEN.getCacheKey(currUserId.toString()));
        // 构造查询条件
        Page<Note> notePage = new Page<>(current, 1);
        notePage.addOrder(OrderItem.desc("update_time"));
        LambdaQueryWrapper<Note> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Note::getAccount, userCacheBo.getAccount());
        // 查询笔记
        this.page(notePage, queryWrapper);
        // 准备数据
        List<Book> books = bookService.getBookList();
        // 构造结果集
        PageR<NoteDetailResp> pageR = new PageR<>();
        BeanUtils.copyProperties(notePage, pageR, "records");
        Note note = notePage.getRecords().get(0);
        NoteDetailResp noteDetailResp = new NoteDetailResp();
        noteDetailResp.setType(note.getType());
        noteDetailResp.setNoteContent(note.getContent());
        noteDetailResp.setTime(note.getUpdateTime());
        if (note.getType().equals(AppProperties.ITEM_TYPE_SUBJECT)){
            SubjectItem subjectItem = subjectItemService.getSubjectItemById(note.getItemId());
            List<BookItem> bookItems = bookItemMapper.selectList(new LambdaQueryWrapper<BookItem>().eq(BookItem::getItemId, subjectItem.getId()));
            List<BookListResult> bookList = bookService.getBooksOfItem(subjectItem.getId(), bookItems, books).get(0);
            Collections.reverse(bookList);
            noteDetailResp.setChapter(bookList.stream().map(BookListResult::getName).collect(Collectors.joining("/")));
            // 封装其他信息
            noteDetailResp.setId(subjectItem.getId());
            Code difficulty = codeService.getById(subjectItem.getDifficultyId());
            noteDetailResp.setDifficulty(difficulty != null ? difficulty.getName() : null);
            noteDetailResp.setKnowledgePoints(Arrays.asList(subjectItem.getKnowledgePoint().split("\\|")));
            noteDetailResp.setContent(subjectItem.getContent());
            noteDetailResp.setAge(subjectItem.getAge());
            noteDetailResp.setGender(subjectItem.getGender());
            // 查询是否收藏
            LambdaQueryWrapper<Collect> collectLambdaQueryWrapper = new LambdaQueryWrapper<>();
            collectLambdaQueryWrapper.eq(Collect::getItemId, subjectItem.getId()).eq(Collect::getAccount, userCacheBo.getAccount());
            noteDetailResp.setIsCollect(collectService.count(collectLambdaQueryWrapper) != 0 ? 1 : 0);
            // 查询关联图片
            List<Image> images = imageService.getImagesByItemId(subjectItem.getId());
            noteDetailResp.setImages(images.stream().map(Image::getRemoteFileUrl).collect(Collectors.toList()));
            // 获取总分
            noteDetailResp.setScore(itemService.calculateItemTotalScore(subjectItem));
            // 构造问题，计算总分
            List<NoteDetailResp.SubjectQuestion> questions = new ArrayList<>();
            if (StringUtils.hasText(subjectItem.getAnsDiagnose())) {
                questions.add(new NoteDetailResp.SubjectQuestion("diagnose", "请诊断该患者的病症是什么？", Arrays.asList(subjectItem.getTipDiagnose().split("\\|")), subjectItem.getAnsDiagnose()));
            }
            if (StringUtils.hasText(subjectItem.getAnsCause())){
                questions.add(new NoteDetailResp.SubjectQuestion("cause", "请问该患者的病机是什么？", Arrays.asList(subjectItem.getTipCause().split("\\|")), subjectItem.getAnsCause()));
            }
            if (StringUtils.hasText(subjectItem.getAnsMethod())){
                questions.add(new NoteDetailResp.SubjectQuestion("method", "请问该患者的治法是什么？", Arrays.asList(subjectItem.getTipMethod().split("\\|")), subjectItem.getAnsMethod()));
            }
            if (StringUtils.hasText(subjectItem.getAnsPrescription())){
                questions.add(new NoteDetailResp.SubjectQuestion("prescription", "请问该患者开的处方是什么？", Arrays.asList(subjectItem.getTipPrescription().split("\\|")), subjectItem.getAnsPrescription()));
            }
            if (StringUtils.hasText(subjectItem.getAnsMedicine())){
                questions.add(new NoteDetailResp.SubjectQuestion("medicine", "请问该患者开的药物是什么？", Arrays.asList(subjectItem.getTipMedicine().split("\\|")), subjectItem.getAnsMedicine()));

            }
            noteDetailResp.setQuestions(questions);
        }else {
            ClozeItem clozeItem = clozeItemService.getClozeItemById(note.getItemId());
            List<BookItem> bookItems = bookItemMapper.selectList(new LambdaQueryWrapper<BookItem>().eq(BookItem::getItemId, clozeItem.getId()));
            noteDetailResp.setAns(clozeItem.getAns());
            List<BookListResult> bookList = bookService.getBooksOfItem(clozeItem.getId(), bookItems, books).get(0);
            Collections.reverse(bookList);
            noteDetailResp.setChapter(bookList.stream().map(BookListResult::getName).collect(Collectors.joining("/")));
            // 查询难易级别
            Code difficulty = codeService.getById(clozeItem.getDifficultyId());
            noteDetailResp.setDifficulty(difficulty != null ? difficulty.getName() : null);
            noteDetailResp.setKnowledgePoints(Arrays.asList(clozeItem.getKnowledgePoint().split("\\|")));
            noteDetailResp.setContent(clozeItem.getMarkContent());
            // 查询是否收藏
            LambdaQueryWrapper<Collect> collectLambdaQueryWrapper = new LambdaQueryWrapper<>();
            collectLambdaQueryWrapper.eq(Collect::getItemId, clozeItem.getId()).eq(Collect::getAccount, userCacheBo.getAccount());
            noteDetailResp.setIsCollect(collectService.count(collectLambdaQueryWrapper) != 0 ? 1 : 0);
            // 查询关联图片
            List<Image> images = imageService.getImagesByItemId(clozeItem.getId());
            noteDetailResp.setImages(images.stream().map(Image::getRemoteFileUrl).collect(Collectors.toList()));
            // 计算总分
            noteDetailResp.setScore(itemService.calculateItemTotalScore(clozeItem));
        }
        pageR.setRecords(new ArrayList<NoteDetailResp>(){{
            add(noteDetailResp);
        }});
        return pageR;
    }

    /**
     * 转换笔记实体对象为列表展示类
     * @param notes 笔记实体对象集合
     * @return 列表展示类集合
     */
    private List<NoteListResult> transferNoteToListResult(List<Note> notes){
        // 将笔记分类并获取题目ID
        List<Long> subjectIds = notes.stream().filter(note -> note.getType().equals(AppProperties.ITEM_TYPE_SUBJECT)).map(Note::getItemId).collect(Collectors.toList());
        List<Long> ClozeIds = notes.stream().filter(note -> note.getType().equals(AppProperties.ITEM_TYPE_CLOZE)).map(Note::getItemId).collect(Collectors.toList());
        // 获取收藏题目
        List<SubjectItem> subjectItems;
        if (!CollectionUtils.isEmpty(subjectIds)) {
            subjectItems = subjectItemService.getBaseMapper().selectBatchIds(subjectIds);
        } else {
            subjectItems = null;
        }
        List<ClozeItem> clozeItems;
        if (!CollectionUtils.isEmpty(ClozeIds)){
            clozeItems = clozeItemService.getBaseMapper().selectBatchIds(ClozeIds);
        }else {
            clozeItems = null;
        }
        // 准备数据
        List<Book> books = bookService.getBookList();
        // 构造结果集
        return notes.stream().map(note -> {
            NoteListResult result = new NoteListResult();
            result.setAccount(note.getAccount());
            result.setId(note.getId());
            result.setType(note.getType());
            result.setItemId(note.getItemId());
            result.setTime(note.getUpdateTime());
            if (note.getType().equals(AppProperties.ITEM_TYPE_SUBJECT) && subjectItems != null) {
                subjectItems.stream().filter(subjectItem -> subjectItem.getId().equals(note.getItemId())).findFirst().ifPresent(subjectItem -> {
                    List<BookItem> bookItems = bookItemMapper.selectList(new LambdaQueryWrapper<BookItem>().eq(BookItem::getItemId, subjectItem.getId()));
                    result.setContent(subjectItem.getContent());
                    List<BookListResult> bookList = bookService.getBooksOfItem(subjectItem.getId(), bookItems, books).get(0);
                    Collections.reverse(bookList);
                    result.setChapter(bookList.stream().map(BookListResult::getName).collect(Collectors.joining("/")));
                });
            } else if (note.getType().equals(AppProperties.ITEM_TYPE_CLOZE) && clozeItems != null) {
                clozeItems.stream().filter(clozeItem -> clozeItem.getId().equals(note.getItemId())).findFirst().ifPresent(clozeItem -> {
                    List<BookItem> bookItems = bookItemMapper.selectList(new LambdaQueryWrapper<BookItem>().eq(BookItem::getItemId, clozeItem.getId()));
                    result.setContent(clozeItem.getMarkContent());
                    List<BookListResult> bookList = bookService.getBooksOfItem(clozeItem.getId(), bookItems, books).get(0);
                    Collections.reverse(bookList);
                    result.setChapter(bookList.stream().map(BookListResult::getName).collect(Collectors.joining("/")));
                });
            }
            return result;
        }).collect(Collectors.toList());
    }

    @Override
    public PageR<NoteListResult> getNoteListByTeacher(Integer page, Integer pageSize, String account,Long currUserId, String currAccount){
        Page<Note> notePage = new Page<>(page, pageSize);
        notePage.addOrder(OrderItem.desc("update_time"));

        // 构造查询条件
        LambdaQueryWrapper<Note> queryWrapper = new LambdaQueryWrapper<>();
        if (!roleService.isAdministrator(currUserId)) {// 如果不是管理员则仅可以查看自己所教班级的数据
            List<String> accounts = teacherMapper.selectStudentAccountByTeacherAccount(currAccount);
            queryWrapper.in(!CollectionUtils.isEmpty(accounts), Note::getAccount, accounts);
            queryWrapper.apply(CollectionUtils.isEmpty(accounts), "1 != 1");
        }
        queryWrapper.eq(StringUtils.hasText(account), Note::getAccount, account);
        this.page(notePage, queryWrapper);

        // 构造结果集
        PageR<NoteListResult> pageR = new PageR<>();
        BeanUtils.copyProperties(notePage, pageR, "records");
        List<NoteListResult> noteListResults = this.transferNoteToListResult(notePage.getRecords());
        noteListResults.forEach(noteListResult -> {
            User user = userService.getUserByAccount(noteListResult.getAccount());
            noteListResult.setName(user.getName());
            Optional.ofNullable(user.getAvatar()).ifPresent(id -> noteListResult.setAvatarUrl(imageService.getImageById(id).getRemoteFileUrl()));
        });
        pageR.setRecords(noteListResults);
        return pageR;
    }

}




